package com.sword.ms_bwk.block;

import com.sword.ms_bwk.ObjectInitialization;
import com.sword.ms_bwk.Utils;
import com.sword.ms_bwk.block.tile.ContainerFurnitureBlockEntity;
import com.sword.ms_bwk.block.tile.NormalFurnitureBlockEntity;
import com.sword.ms_bwk.furniture.AbstractFurnitureWithProperty;
import com.sword.ms_bwk.furniture.util.GUIType;
import com.sword.ms_bwk.furniture.util.UtilPackage;
import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider;
import net.minecraft.core.BlockPos;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.sounds.SoundSource;
import net.minecraft.world.*;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.context.BlockPlaceContext;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.*;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.StateDefinition;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
import net.minecraft.world.level.block.state.properties.BooleanProperty;
import net.minecraft.world.level.material.Material;
import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.shapes.CollisionContext;
import net.minecraft.world.phys.shapes.VoxelShape;
import net.minecraftforge.registries.RegistryObject;
import software.bernie.geckolib3.core.IAnimatable;
import software.bernie.geckolib3.model.AnimatedGeoModel;
import software.bernie.geckolib3.renderers.geo.GeoBlockRenderer;

import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.Random;

public class FurnitureBlock extends HorizontalDirectionalBlock implements EntityBlock {

    public static ArrayList<FurnitureBlock> furnitureList = new ArrayList<>();

    public RegistryObject<BlockEntityType<?>> blockEntity;

    private final AbstractFurnitureWithProperty furniture;

    private static final BooleanProperty OPEN_STATE = BlockStateProperties.OPEN;
    private static final BooleanProperty KEEP_STATE = BooleanProperty.create("keep");

    public FurnitureBlock(AbstractFurnitureWithProperty furniture) {
        super(Properties.of(Material.STONE).noCollission().lightLevel((state) -> furniture.isLight ? 15 : 0));

        this.furniture = furniture;

        this.registerDefaultState(this.getStateDefinition().any().setValue(OPEN_STATE, Boolean.valueOf(false)).setValue(KEEP_STATE, Boolean.valueOf(false)));

        blockEntity = ObjectInitialization.TILE_ENTITY_TYPES.register(furniture.name + "_tile_entity", () -> BlockEntityType.Builder.of(this::getBlockEntity, this).build(null));
        furnitureList.add(this);
    }

    //获取BlockEntity类型
    public BlockEntity getBlockEntity(BlockPos pPos, BlockState pBlockStat) {
        return switch (furniture.guiType) {
            case Container -> new ContainerFurnitureBlockEntity(blockEntity.get(), this, pPos, pBlockStat);

            //待修改
            case Furnace -> new ContainerFurnitureBlockEntity(blockEntity.get(), this, pPos, pBlockStat);
            //TODO..

            default -> new NormalFurnitureBlockEntity(blockEntity.get(), pPos, pBlockStat);
        };
    }

    //添加放置方块的方向
    @Override
    public BlockState getStateForPlacement(BlockPlaceContext pContext) {
        return this.defaultBlockState().setValue(FACING, pContext.getHorizontalDirection().getOpposite());
    }

    //添加方块属性
    @Override
    protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> pBuilder) {
        pBuilder.add(FACING, OPEN_STATE, KEEP_STATE);
    }

    //添加新的方块实体
    @Nullable
    @Override
    public BlockEntity newBlockEntity(BlockPos pPos, BlockState pState) {
        return blockEntity.get().create(pPos, pState);
    }

    //设置不渲染方块
    @Override
    public RenderShape getRenderShape(BlockState state) {
        return RenderShape.ENTITYBLOCK_ANIMATED;
    }

    //设置方块右击事件
    @Override
    public InteractionResult use(BlockState pState, Level pLevel, BlockPos pPos, Player pPlayer, InteractionHand pHand, BlockHitResult pHit) {
        GUIType type = furniture.guiType;
        if (type == GUIType.Container || type == GUIType.Furnace) {
            pState = pState.setValue(OPEN_STATE, Boolean.valueOf(true));
            pLevel.setBlock(pPos, pState, 2);
            if (pLevel.isClientSide) {
                pLevel.playLocalSound((double)pPos.getX() + 0.5D, (double)pPos.getY() + 0.5D, (double)pPos.getZ() + 0.5D, furniture.up.soundPackage.OPEN_SOUND.get(), SoundSource.BLOCKS,1.0F, 1.0F, false);
                return InteractionResult.SUCCESS;
            } else {
                pPlayer.openMenu((MenuProvider) pLevel.getBlockEntity(pPos));
                return InteractionResult.CONSUME;
            }
        }
        return InteractionResult.PASS;
    }

    //家具常驻音效
    @Override
    public void animateTick(BlockState pState, Level pLevel, BlockPos pPos, Random pRandom) {
        if (furniture.guiType != GUIType.Null && furniture.up.soundPackage.isKeepState()) {
            double d0 = (double)pPos.getX() + 0.5D;
            double d1 = (double)pPos.getY() + 0.5D;
            double d2 = (double)pPos.getZ() + 0.5D;
            if (pRandom.nextDouble() < 0.1D) {
                pLevel.playLocalSound(d0, d1, d2, furniture.up.soundPackage.STANDBY_SOUND.get(), SoundSource.BLOCKS, 1.0F, 1.0F, false);
            }
        }
    }

    //设置形状，用于判断碰撞箱
    @Override
    public VoxelShape getShape(BlockState pState, BlockGetter pLevel, BlockPos pPos, CollisionContext pContext) {
        return furniture.getShape(pState, pLevel, pPos, pContext);
    }

    public class Renderer<E extends BlockEntity & IAnimatable> extends GeoBlockRenderer<E> {
        public Renderer(BlockEntityRendererProvider.Context renderManager) {
            super(renderManager, new Model());
        }
    }

    public class Model<E extends BlockEntity & IAnimatable> extends AnimatedGeoModel<E> {
        @Override
        public ResourceLocation getModelLocation(E object) {
            return new ResourceLocation(Utils.MOD_ID, furniture.guiType == GUIType.Null || !object.getBlockState().getValue(KEEP_STATE) ? furniture.geoPath : furniture.up.animationPackage.keepGeoPath);
        }

        @Override
        public ResourceLocation getTextureLocation(E object) {
            return new ResourceLocation(Utils.MOD_ID, furniture.texturePath);
        }

        @Override
        public ResourceLocation getAnimationFileLocation(E animatable) {
            return new ResourceLocation(Utils.MOD_ID, furniture.guiType != GUIType.Null ? furniture.up.animationPackage.getPath() : "");
        }
    }

    public UtilPackage getUtilPackage() {
        return furniture.up;
    }

    public String getAnime(int index) {
        return furniture.up.animationPackage.getAnime(index);
    }

    public String getFurnitureName() {
        return furniture.name;
    }

    public BooleanProperty getOpenState() {
        return OPEN_STATE;
    }

    public BooleanProperty setKeepState() {
        return KEEP_STATE;
    }
}
